package me.eachann.session

import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.util.Base64
import me.eachann.session.SessionManager.notifyOnSessionStateChanged
import java.io.*

/**
 * 默认使用SP方式存储数据
 */
class PreferencesSessionManager : ISessionManager {
    private var mSharedPreferences: SharedPreferences? = null

    override fun isExist(cls: Class<*>): Boolean {
        return getSession<Class<*>>(cls) != null
    }

    @SuppressLint("ApplySharedPref")
    override fun remove(cls: Class<*>) {
        mSharedPreferences?.edit()?.remove(cls.simpleName)?.commit()
    }
    @SuppressLint("ApplySharedPref")
    override fun clearAll() {
        mSharedPreferences?.edit()?.clear()?.commit()
    }

    @Suppress("UNCHECKED_CAST")
    override fun <T : Serializable> getSession(cls: Class<*>): T? {
        try {
            val result = read(cls.simpleName)
            return if (result == null) null else result as T
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return null
    }

    override fun <T : Serializable> setSession(session: T) {
        writeObject(session)
        notifyOnSessionStateChanged(session)
    }

    init {
        try {
            val context = SessionProvider.instance
                    ?: throw NullPointerException("默认使用的SessionManger为偏好，请初始化Context")
            val configName = context.packageName.toString() + ".session"
            mSharedPreferences = context.getSharedPreferences(configName, Context.MODE_PRIVATE)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 根据className存储对象
     */
    private fun <T : Serializable> writeObject(t: T) {
        writeObjectByName(t.javaClass.simpleName, t)
    }

    /**
     * 根据key存储对象数据
     */
    private fun <T : Serializable> writeObjectByName(key: String, t: T) {
        var outputStream: ByteArrayOutputStream? = null
        var oos: ObjectOutputStream? = null
        try {
            outputStream = ByteArrayOutputStream()
            oos = ObjectOutputStream(outputStream)
            oos.writeObject(t)
            val base64FromObject = Base64.encodeToString(outputStream.toByteArray(), 0)
            mSharedPreferences?.edit()?.putString(key, base64FromObject)?.apply()
        } catch (ex: IOException) {
            ex.printStackTrace()
        } finally {
            oos?.close()
            outputStream?.close()
        }

    }


    /**
     * 根据key读取对象数据
     */
    private fun read(key: String): Any? {
        var obj: Any?
        val productBase64 = mSharedPreferences?.getString(key, null)
        productBase64?.let {
            val base64 = Base64.decode(productBase64.toByteArray(), 0)
            var bais: ByteArrayInputStream? = null
            var bis: ObjectInputStream? = null
            try {
                bais = ByteArrayInputStream(base64)
                bis = ObjectInputStream(bais)
                obj = bis.readObject()
            } catch (ex: Exception) {
                ex.printStackTrace()
                return null
            } finally {
                bis?.close()
                bais?.close()
            }
            return obj
        }
        return null
    }
}